require "engine.class"
require "engine.Object"
require "engine.interface.ObjectActivable"
require "engine.interface.ObjectIdentify"

local Stats = require("engine.interface.ActorStats")
local DamageType = require("engine.DamageType")

module(..., package.seeall, class.inherit(
	engine.Object,
	engine.interface.ObjectActivable,
	engine.interface.ObjectIdentify
))

function _M:init(t, no_default)
	engine.Object.init(self, t, no_default)
	engine.interface.ObjectActivable.init(self, t)
	engine.interface.ObjectIdentify.init(self, t)
end

--- Can this object act at all
-- Most object will want to anwser false, only recharging and stuff needs them
function _M:canAct()
	if self.power_regen or self.use_talent then return true end
	return false
end

--- Do something when its your turn
-- For objects this mostly is to recharge them
-- By default, does nothing at all
function _M:act()
	self:regenPower()
	self:cooldownTalents()
	self:useEnergy()
end

--- Use the object (quaff, read, ...)
function _M:use(who, typ)
	local types = {}
	if self:canUseObject() then types[#types+1] = "use" end

	if not typ and #types == 1 then typ = types[1] end

	if typ == "use" then
		who:useEnergy()
		if self.use_sound then game:playSoundNear(who, self.use_sound) end
		return self:useObject(who)
	end
end

--- Returns a tooltip for the object
function _M:tooltip()
	return self:getDesc{do_color=true}
end

--- Gets the color in which to display the object in lists
function _M:getDisplayColor()
	if self.egoed then return {0, 255, 128}, "#00FF80#"
	elseif self.unique then return {255, 255, 0}, "#FFFF00#"
	else return {255, 255, 255}, "#FFFFFF#"
	end
end

--- Gets the full name of the object
function _M:getName(t)
	t = t or {}
	local qty = self:getNumber()
	local name = self.name

	-- To extend later
	name = name:gsub("~", ""):gsub("&", "a"):gsub("#([^#]+)#", function(attr)
		return self:descAttribute(attr)
	end)

	if not t.do_color then
		if qty == 1 or t.no_count then return name
		else return qty.." "..name
		end
	else
		local _, c = self:getDisplayColor()
		local ds = self:getDisplayString()
		if qty == 1 or t.no_count then return c..ds..name.."#LAST#"
		else return c..qty.." "..ds..name.."#LAST#"
		end
	end
end

--- Gets the full textual desc of the object without the name and requirements
function _M:getTextualDesc()
	local desc = {}

	desc[#desc+1] = ("Type: %s / %s"):format(self.type, self.subtype)

	local desc_wielder = function(w)
		if w.combat_atk or w.combat_dam or w.combat_apr then desc[#desc+1] = ("To Hit: %d, To Damage: %d"):format(w.combat_atk or 0, w.combat_dam or 0) end
		if w.combat_armor or w.combat_def then desc[#desc+1] = ("Armor %d, Defense %d"):format(w.combat_armor or 0, w.combat_def or 0) end
		if w.fatigue then desc[#desc+1] = ("Fatigue %d%%"):format(w.fatigue) end

		if w.inc_stats then
			local dm = {}
			for stat, i in pairs(w.inc_stats) do
				dm[#dm+1] = ("%d %s"):format(i, Stats.stats_def[stat].name)
			end
			desc[#desc+1] = ("Increases stats: %s."):format(table.concat(dm, ','))
		end

		if w.on_melee_hit then
			local rs = {}
			for typ, dam in pairs(w.on_melee_hit) do
				rs[#rs+1] = ("%d %s"):format(dam, DamageType.dam_def[typ].name)
			end
			desc[#desc+1] = ("Damage when hit: %s."):format(table.concat(rs, ','))
		end

		if w.resists then
			local rs = {}
			for res, i in pairs(w.resists) do
				rs[#rs+1] = ("%d%% %s"):format(i, res == "all" and "all" or DamageType.dam_def[res].name)
			end
			desc[#desc+1] = ("Increases resistances: %s."):format(table.concat(rs, ','))
		end
	end

	desc_wielder(self.wielder or {})

	local use_desc = self:getUseDesc()
	if use_desc then desc[#desc+1] = use_desc end

	return desc
end

--- Gets the full desc of the object
function _M:getDesc(name_param)
	local _, c = self:getDisplayColor()
	local desc = { c..self:getName(name_param).."#FFFFFF#", self.desc }

	local reqs = self:getRequirementDesc(game.player)
	if reqs then
		desc[#desc+1] = reqs
	end

	if self.quantity then
		desc[#desc+1] = ("Quantity: %d"):format(self.quantity)
	end

	desc[#desc+1] = ("Type: %s / %s"):format(self.type, self.subtype)

	local desc_wielder = function(w)
		if w.combat_atk or w.combat_dam then desc[#desc+1] = ("To Hit: %d, To Damage: %d"):format(w.combat_atk or 0, w.combat_dam or 0) end
		if w.combat_armor or w.combat_def then desc[#desc+1] = ("Armor %d, Defense %d"):format(w.combat_armor or 0, w.combat_def or 0) end

		if w.inc_stats then
			local dm = {}
			for stat, i in pairs(w.inc_stats) do
				dm[#dm+1] = ("%d %s"):format(i, Stats.stats_def[stat].name)
			end
			desc[#desc+1] = ("Increases stats: %s."):format(table.concat(dm, ','))
		end

		if w.on_melee_hit then
			local rs = {}
			for typ, dam in pairs(w.on_melee_hit) do
				rs[#rs+1] = ("%d %s"):format(dam, DamageType.dam_def[typ].name)
			end
			desc[#desc+1] = ("Damage when hit: %s."):format(table.concat(rs, ','))
		end

		if w.resists then
			local rs = {}
			for res, i in pairs(w.resists) do
				rs[#rs+1] = ("%d%% %s"):format(i, res == "all" and "all" or DamageType.dam_def[res].name)
			end
			desc[#desc+1] = ("Increases resistances: %s."):format(table.concat(rs, ','))
		end
	end

	desc_wielder(self.wielder or {})

	local use_desc = self:getUseDesc()
	if use_desc then desc[#desc+1] = use_desc end

	return table.concat(desc, "\n")
end

local type_sort = {
	potion = 1,
	scroll = 1,
	jewelry = 3,
	weapon = 100,
	armor = 101,
}

--- Sorting by type function
-- By default, sort by type name
function _M:getTypeOrder()
	if self.type and type_sort[self.type] then
		return type_sort[self.type]
	else
		return 99999
	end
end

--- Sorting by type function
-- By default, sort by subtype name
function _M:getSubtypeOrder()
	return self.subtype or ""
end

--- Get item cost
function _M:getPrice()
	return self.cost or 0
end
